/*
 * @author: Jesus Alonso
 * @Date: Nov, 10, 2010
 * 
 */
package uicgas.station;

import java.util.ArrayList;
import java.util.concurrent.ConcurrentLinkedQueue;

import org.apache.log4j.Logger;

import uicgas.globaldata.ActivationData;
import uicgas.globaldata.ClientTypes;
import uicgas.globaldata.ControlMessage;
import uicgas.globaldata.CreditCard;
import uicgas.globaldata.GenericPumpList;
import uicgas.globaldata.MessagePayload;
import uicgas.globaldata.Messages;
import uicgas.globaldata.Password;
import uicgas.globaldata.Pump;
import uicgas.globaldata.PumpState;
import uicgas.globaldata.Register;
import uicgas.globaldata.SelfAnnouncement;
import uicgas.globaldata.States;
import uicgas.globaldata.Transaction;
import uicgas.tools.LogHelper;

public class StationLogic
{

	// arrays to keep track of each pump and register
	private ArrayList<Pump> pump_list;
	private ArrayList<Register> register_list;
	private int pumpCount;
	private int registerCount;

	// queues to manage decommissioned pumps
	// and pumps at which assistance from
	// an operator is needed
	//private DecommissionedPumps decomm_pumps;
	//private AssistanceQueue assistance_needed;
	private ConcurrentLinkedQueue<Pump> decomm_pumps;
	private ConcurrentLinkedQueue<Pump> assistance_needed;

	// objects to communicate with
	// pumps and registers through Socket
	private Server_Comm pumpServer;
	private Server_Comm registerServer;
	private boolean pumpServerStarted;
	private boolean registerServerStarted;

	// password for recommissioning a pump
	private String recomm_password;
	private boolean recomm_authorized;

	//console messages and logging
	private static final Logger LOGGER = LogHelper
			.getLogger(StationLogic.class);

	//default constructor
	public StationLogic()
	{

	}

	//non default constructor
	public StationLogic(int pumpPort, int registerPort, String recommPwd)
	{
		pump_list = new ArrayList<Pump>(20);
		register_list = new ArrayList<Register>(5);
		pumpCount = 0;
		registerCount = 0;

		decomm_pumps = new ConcurrentLinkedQueue<Pump>();
		assistance_needed = new ConcurrentLinkedQueue<Pump>();

		if (pumpPort == registerPort)
		{
			pumpServer = new Server_Comm(50000, this, ClientTypes.PUMP);
			registerServer = new Server_Comm(50001, this, ClientTypes.REGISTER);
		}
		else
		{

			if (pumpPort > 49152 && pumpPort < 65535)
				pumpServer = new Server_Comm(pumpPort, this, ClientTypes.PUMP);
			else
				pumpServer = new Server_Comm(50000, this, ClientTypes.PUMP);

			if (registerPort > 49152 && registerPort < 65535)
				registerServer = new Server_Comm(registerPort, this,
						ClientTypes.REGISTER);
			else
				registerServer = new Server_Comm(50001, this,
						ClientTypes.REGISTER);
		}
		recomm_authorized = false;
		recomm_password = recommPwd;
	}

	//	public void passThroughLogic()
	//	{
	//		pumpServer.selectOnServer();
	//		registerServer.selectOnServer();
	//	}

	/**
	 * Starts the Server_Comm for Pumps.
	 * 
	 * @return void
	 */
	public void startPumpServer()
	{
		if (!pumpServerStarted)
		{
			if (pumpServer.startServer() == 0)
				pumpServerStarted = true;
			else
				System.out
						.println("Error starting pump server from StationLogic...");
		}
		else
			System.out.println("Pump server already started...");
	}

	/**
	 * Starts the Server_Comm for Registers.
	 * 
	 * @return void
	 */
	public void startRegisterServer()
	{
		if (!registerServerStarted)
		{
			if (registerServer.startServer() == 0)
				registerServerStarted = true;
			else
				System.out
						.println("Error starting register server from StationLogic...");
		}
		else
			System.out.println("Register server already started...");
	}

	//////////////////////
	// RemoteCommand logic
	//////////////////////

	/**
	* This handles the ConnectPump command logic.
	*
	* The Server_Comm calls this method when it receives
	* a ControlMessage with a message of CONNECTPUMP.
	* 
	* This method adds a pump to the pump arraylist
	* and makes sure that the number of connected pumps
	* does not exceed 20. 
	*
	* @param  data This contains a SelfAnnouncement with a valid ID to insert into list
	* @return void
	*/
	public void connectPump(MessagePayload data)
	{
		// Add pump to arraylist of pumps
		try
		{
			if (data != null)
			{
				SelfAnnouncement announcement = (SelfAnnouncement) data;
				Pump newPump = new Pump(announcement.getID(), null, 0.0,
						States.DEACTIVATED);

				if (pumpCount < 20)
				{

					// add pump as long as there is no Pump
					// with the same ID in the arraylist
					if (pump_list.indexOf(newPump) == -1)
					{
						pump_list.add(newPump);
						pumpCount++;
						//pumpServer already has
						//Socket for this pump
						System.out.println("Pump " + announcement.getID()
								+ " connected...");
					}
					else
					{
						System.out.println("Pump No. " + newPump.getID()
								+ " already connected.");
					}
				}
				else
				{
					System.out.println("Cannot add Pump No. " + newPump.getID()
							+ ". Exceeded Pump limit of 20");
				}
			}
		}
		catch (ClassCastException e)
		{
			LOGGER.error(LogHelper.LOG_LAYER_ONE
					+ "Wrong payload type to connectPump()...");
		}
	}

	/**
	* This handles the ConnectRegister command logic.
	*
	* The Server_Comm calls this method when it receives
	* a ControlMessage with a message of CONNECTREGISTER.
	* 
	* This method adds a register to the register arraylist
	* and makes sure that the number of connected registers
	* does not exceed 5. 
	*
	* @param  data This contains a SelfAnnouncement with a valid ID to insert into list
	* @return void
	*/
	public void connectRegister(MessagePayload data)
	{
		// Add register to arraylist of pumps
		try
		{
			if (data != null)
			{
				SelfAnnouncement announcement = (SelfAnnouncement) data;
				Register newRegister = new Register(announcement.getID());

				if (registerCount < 5)
				{

					// add register as long as there is no Register
					// with the same ID in the arraylist
					if (register_list.indexOf(newRegister) == -1)
					{
						register_list.add(newRegister);
						registerCount++;
						//registerServer already has
						//Socket for this pump

						System.out.println("Register " + announcement.getID()
								+ " connected...");
					}
					else
					{
						System.out.println("Register No. "
								+ newRegister.getID() + " already connected.");
					}
				}
				else
				{
					System.out.println("Cannot add Register No. "
							+ newRegister.getID()
							+ ". Exceeded Register limit of 5");
				}
			}
		}
		catch (ClassCastException e)
		{
			LOGGER.error(LogHelper.LOG_LAYER_ONE
					+ "Wrong payload type to connectRegister()...");
		}
	}

	/**
	 * This handles the ChangePumpState command logic.
	 *
	 * The Server_Comm calls this method when it receives
	 * a ControlMessage with a message of CHANGEPUMPSTATE.
	 * 
	 * This method ensures that the state of a pump is changed
	 * properly when a pump requests to change its state. A control
	 * message is forwarded to the register to change the state of 
	 * this pump that just changed.
	 *  
	 * @param  data This contains a StateChange object with a valid ID of a pump, the current state of type States of the pump and a new state to change to.
	 * @return void
	 */
	public void changePumpState(MessagePayload data)
	{
		try
		{
			if (data == null)
				return;
			PumpState stateChange = (PumpState) data;
			int pumpIndex = pump_list.indexOf(new Pump(stateChange.getPumpID(),
					null, 0.0, States.DEACTIVATED));
			if (pumpIndex < 0)
			{
				System.out.println("Cannot change state of Pump No. "
						+ stateChange.getPumpID() + ". Pump nonexistant.");
				return;
			}
			Pump currentPump = pump_list.get(pumpIndex);

			// Check if the current state matches
			if (currentPump.getState() == stateChange.getCurrentState())
			{
				// Check if change is trivial
				if (currentPump.getState() != stateChange.getNewState())
				{

					// Change state
					currentPump.setState(stateChange.getNewState());

					//should clear prepayment information for currentPump
					if (stateChange.getNewState() == States.DEACTIVATED
							|| stateChange.getNewState() == States.DECOMMISSIONED)
						currentPump.setPrepaid(0.0);

					// Send a ChangePumpState command to register
					ControlMessage toRegister = new ControlMessage(
							Messages.CHANGEPUMPSTATE, data);

					//using Server_Comm.send(0, message); with parameter -1 broadcasts to all connected components
					//either pumps or registers
					if (registerServer.sendMessage(toRegister, -1) != 0)
						System.out
								.println("Failed sending register pump state change command...");

				}
				else
					System.out.println("Pump No. " + currentPump.getID()
							+ " already " + stateChange.getCurrentState());

			}
			else
				System.out
						.println("Received current state does not match Current state of Pump No. "
								+ currentPump.getID());

		}
		catch (ClassCastException e)
		{
			LOGGER.error(LogHelper.LOG_LAYER_ONE
					+ "Wrong payload type to changePumpState()...");
		}
	}

	/**
	 * This handles the AnnounceDecommPumps command logic.
	 *
	 * The Server_Comm calls this method when it receives
	 * a ControlMessage with a message of ANNOUNCEDECOMMPUMPS.
	 * 
	 * This method simply sends the decomm_pumps list to the register
	 * identified in the payload SelfAnnouncement.
	 *  
	 * @param  data This contains a SelfAnnouncement with a valid ID to reply to.
	 * @return void
	 */
	public void announceDecommPumps(MessagePayload data)
	{
		//data contains ID of register that requested info
		try
		{
			if (data != null)
			{
				SelfAnnouncement reg = (SelfAnnouncement) data;
				int regID = reg.getID();

				GenericPumpList decommPumps = new GenericPumpList(decomm_pumps);
				ControlMessage toRegister = new ControlMessage(
						Messages.ANNOUNCEDECOMMPUMPS, decommPumps);
				registerServer.sendMessage(toRegister, regID);
			}
		}
		catch (ClassCastException e)
		{
			LOGGER.error(LogHelper.LOG_LAYER_ONE
					+ "Wrong payload type to announceDecommPumps()...");
		}
	}

	/**
	 * This handles the AnnounceAllConnectedPumps command logic.
	 *
	 * The Server_Comm calls this method when it receives
	 * a ControlMessage with a message of ANNOUNCEALLCONNECTEDPUMPS.
	 * This method sends both the pump arraylist and the decommission queue
	 * to the register specified in the SelfAnnouncement. 
	 *  
	 * @param  data This contains a SelfAnnouncement with a valid ID to insert into list
	 * @return void
	 */
	public void announceAllConnectedPumps(MessagePayload data)
	{
		//data contains ID of register that requested info
		try
		{
			if (data != null)
			{
				SelfAnnouncement reg = (SelfAnnouncement) data;
				int regID = reg.getID();

				if (decomm_pumps == null)
					System.exit(0);
				GenericPumpList pump_lists = new GenericPumpList(decomm_pumps,
						pump_list);
				ControlMessage toRegister = new ControlMessage(
						Messages.ANNOUNCEALLCONNECTEDPUMPS, pump_lists);
				registerServer.sendMessage(toRegister, regID);
			}
		}
		catch (ClassCastException e)
		{
			LOGGER.error(LogHelper.LOG_LAYER_ONE
					+ "Wrong payload type to announceDecommPumps()...");
		}
	}

	/**
	 * This handles the AnnouncePumpState command logic.
	 *
	 * The Server_Comm calls this method when it receives
	 * a ControlMessage with a message of ANNOUNCEPUMPSTATE.
	 * 
	 * This method sends a reply to the register that sent this 
	 * control message. The reply is a  PumpState object with
	 * the current state set to the current state of the requested
	 * pump.
	 *  
	 * @param  data This contains a SelfAnnouncement with a valid ID 
	 * of the requested pump and the ID of the source register.
	 * @return void
	 */
	public void announcePumpState(MessagePayload data)
	{
		//data containsID of register that requested info
		try
		{
			if (data != null)
			{
				SelfAnnouncement reg = (SelfAnnouncement) data;
				int regID = reg.getID();
				int pumpID = reg.getIDofRequested();

				Pump requested = new Pump(pumpID, null, 0, null);

				if (pump_list.indexOf(requested) >= 0)
				{
					requested = pump_list.get(pump_list.indexOf(requested));
					PumpState state = new PumpState(requested.getState(),
							requested.getID());

					//ControlMessage toRegister = new ControlMessage(
					//	Messages.ANNOUNCEPUMPSTATE, state);

					//must use new statereply message
					//or just send command to pump
					ControlMessage toRegister = new ControlMessage(
							Messages.STATEREPLY, state);
					registerServer.sendMessage(toRegister, regID);
				}
			}
		}
		catch (ClassCastException e)
		{
			LOGGER.error(LogHelper.LOG_LAYER_ONE
					+ "Wrong payload type to announcePumpState()...");
		}
	}

	/**
	 * This handles the NotifyRegisterAssistanceNeeded command logic.
	 *
	 * The Server_Comm calls this method when it receives
	 * a ControlMessage with a message of NOTIFYREGISTERASSISTANCENEEDED.
	 * 
	 * This method forwards the NOTIFYREGISTERASSISTANCENEEDED message
	 * to all the connected registers through a Server_Comm broadcast.
	 *  
	 * @param  data This contains a SelfAnnouncement with a valid ID of
	 * the pump that needs assistance.
	 * @return void
	 */
	public void notifyRegisterAssistanceNeeded(MessagePayload data)
	{
		// data field is valid
		// data is a SelfAnnouncement from the pump that needs assistance
		// add pump data.ID to the queue and send register revised queue
		try
		{
			if (data != null)
			{
				SelfAnnouncement pump = (SelfAnnouncement) data;
				int pumpID = pump.getID();

				Pump toAssist = new Pump(pumpID, null, 0, null);
				if (pump_list.indexOf(toAssist) >= 0)
				{
					toAssist = pump_list.get(pump_list.indexOf(toAssist));

					if (!assistance_needed.contains(toAssist))
						assistance_needed.offer(toAssist);

					//Broadcast to all registers using -1
					GenericPumpList assistance = new GenericPumpList(
							assistance_needed);
					ControlMessage toRegister = new ControlMessage(
							Messages.NOTIFYASSISTANCE, assistance);
					registerServer.sendMessage(toRegister, -1);

				}
			}
		}
		catch (ClassCastException e)
		{
			LOGGER.error(LogHelper.LOG_LAYER_ONE
					+ "Wrong payload type to announcePumpState()...");
		}
	}

	/**
	 * This handles the ChargeCreditCard command logic.
	 *
	 * The Server_Comm calls this method when it receives
	 * a ControlMessage with a message of CHARGECREDITCARD.
	 * 
	 * This method uses the Server_Comm method transactCreditCard()
	 * to finish a credit card transaction for gas that was either
	 * prepaid or purchased at a pump.
	 *  
	 * @param  data This contains a Transaction object that contains
	 * the credit card to charge and the amount of the sale to charge.
	 * @return void
	 */
	public void chargeCreditCard(MessagePayload data)
	{
		//data contains a Transaction
		try
		{
			if (data != null)
			{
				Transaction transaction = (Transaction) data;
				
				int pumpID=transaction.getPumpID();
				
				Pump pump=pump_list.get(pump_list.indexOf(new Pump(pumpID, null, 0.0, States.DEACTIVATED)));
				
				pump.setTransaction(transaction);
				registerServer.transactCreditCard(transaction);
			}
		}
		catch (ClassCastException e)
		{
			LOGGER.error(LogHelper.LOG_LAYER_ONE
					+ "Wrong payload type to chargeCreditCard()...");
		}
	}

	/**
	 * This handles the ValidateCard command logic.
	 *
	 * The Server_Comm calls this method when it receives
	 * a ControlMessage with a message of VALIDATECARD.
	 * 
	 * This method uses the Server_Comm to validate a credit card
	 * in the message payload. 
	 *  
	 * @param data This contains a CreditCard object that contains
	 * the credit card info to validate. 
	 * @param sourceID This is the ID of whatever client sent this message.
	 * @param sourceType This is reflects what type of client sent this  message.
	 * It could be either a PUMP or a REGISTER.
	 * @return void
	 */
	public void validateCard(MessagePayload data, int sourceID,
			ClientTypes sourceType)
	{
		try
		{
			if (data != null)
			{
				CreditCard card = (CreditCard) data;

				if (sourceType == ClientTypes.PUMP)
					pumpServer.validateCardWithCompany(card, sourceID);
				else
					registerServer.validateCardWithCompany(card, sourceID);
			}
		}
		catch (ClassCastException e)
		{
			LOGGER.error(LogHelper.LOG_LAYER_ONE
					+ "Wrong payload type to validateCard()...");
		}
	}

	/**
	 * This handles the {@link uicgas.station.remotecmds.ActivatePump ActivatePump} command logic.
	 *
	 * The Server_Comm calls this method when it receives
	 * a ControlMessage with a message of ACTIVATEPUMP.
	 * 
	 * This method 
	 *  
	 * @param data This contains a CreditCard object that contains
	 * the credit card info to validate. 
	 * @param sourceID This is the ID of whatever client sent this message.
	 * @param sourceType This is reflects what type of client sent this  message.
	 * It could be either a PUMP or a REGISTER.
	 * @return void
	 */
	public void activatePump(MessagePayload data)
	{
		//data contains ActivationData
		//This method will send activation data to 
		//specified pump. The state change for that
		//pump will come in the form of a command.
		//should also change info of the pump in
		//pump list.

		try
		{
			if (data != null)
			{
				ActivationData activate = (ActivationData) data;
				int destination = activate.getPumpID();

				Pump checkPump = new Pump(destination, null, 0, null);
				Pump toActivate;

				int index = pump_list.indexOf(checkPump);
				if (activate.getAmountPrepaid() >= 0.00)
				{
					if (index >= 0)
					{
						toActivate = pump_list.get(index);

						ControlMessage message = new ControlMessage(
								Messages.ACTIVATEPUMP, data);
						if (pumpServer.sendMessage(message, destination) != 0)
							System.out
									.println("Failed sending activation signal to Pump: "
											+ destination);

						toActivate.setState(States.ACTIVATED);
						toActivate.setPrepaid(activate.getAmountPrepaid());

					}
					else
						System.out
								.println("Pump ID in ActivationData invalid...");
				}
			}
		}
		catch (ClassCastException e)
		{
			LOGGER.error(LogHelper.LOG_LAYER_ONE
					+ "Wrong payload type to activatePump()...");
		}
	}

	public void deactivatePump(MessagePayload data)
	{
		//data contains SelfAnnouncement
		try
		{
			if (data != null)
			{
				SelfAnnouncement deactivate = (SelfAnnouncement) data;
				int destination = deactivate.getIDofRequested();

				Pump checkPump = new Pump(destination, null, 0, null);

				int index = pump_list.indexOf(checkPump);
				if (index >= 0)
				{
					checkPump = pump_list.get(index);
					checkPump.setState(States.DEACTIVATED);
					checkPump.setPrepaid(0.00);

					ControlMessage message = new ControlMessage(
							Messages.DEACTIVATEPUMP, data);
					if (pumpServer.sendMessage(message, destination) != 0)
						System.out
								.println("Failed sending deactivation signal to Pump: "
										+ destination);
				}
				else
					System.out
							.println("Pump ID in SelfAnnouncement invalid...");
			}
		}
		catch (ClassCastException e)
		{
			LOGGER.error(LogHelper.LOG_LAYER_ONE
					+ "Wrong payload type to deactivatePump()...");
		}
	}

	public void decommissionPump(MessagePayload data)
	{
		//data contains SelfAnnouncement
		//This method must add pump to queue
		//and change the state of the pump.
		//It then sends the decomm message
		//to the pump.
		//Important! Decommissioning a pump removes it
		//from the array list and adds it to the queue.

		try
		{
			if (data != null)
			{
				SelfAnnouncement decomm = (SelfAnnouncement) data;
				int destination = decomm.getIDofRequested();

				Pump toDecommPump = new Pump(destination, null, 0, null);

				int index = pump_list.indexOf(toDecommPump);
				if (index >= 0)
				{
					//removing ensures no commands can reach pump from anywhere
					toDecommPump = pump_list.remove(index);

					toDecommPump.setState(States.DECOMMISSIONED);
					toDecommPump.setPrepaid(0);
					decomm_pumps.offer(toDecommPump);

					ControlMessage message = new ControlMessage(
							Messages.DECOMMISSIONPUMP, data);
					if (pumpServer.sendMessage(message, destination) != 0)
						System.out
								.println("Failed sending decommission signal to Pump: "
										+ destination);

				}
				else
					System.out
							.println("Pump ID in SelfAnnouncement invalid...");
			}
		}
		catch (ClassCastException e)
		{
			LOGGER.error(LogHelper.LOG_LAYER_ONE
					+ "Wrong payload type to decommissionPump()...");
		}
	}

	public void recommissionPump(MessagePayload data)
	{
		//data contains SelfAnnouncement
		//Only recommissions pump if recomm_authorized
		//is set to true. recomm_authorized is only 
		//set to true after password validation from register
		//Important! Recommissioning a pump removes it from the
		//queue and adds it to the array list.
		try
		{
			if (recomm_authorized)
			{
				if (data != null)
				{
					SelfAnnouncement recomm = (SelfAnnouncement) data;
					int destination = recomm.getIDofRequested();

					Pump toRecommPump = new Pump(destination, null, 0, null);

					int index = pump_list.indexOf(toRecommPump);
					if (index < 0)
					{
						//toRecommPump=pump_list.get(index);
						Pump head = decomm_pumps.peek();

						if (toRecommPump.equals(head))
						{
							toRecommPump = decomm_pumps.poll();
							pump_list.add(toRecommPump);

							toRecommPump.setState(States.DEACTIVATED);
							ControlMessage message = new ControlMessage(
									Messages.RECOMMISSIONPUMP, data);
							if (pumpServer.sendMessage(message, destination) != 0)
								System.out
										.println("Failed sending recommission signal to Pump: "
												+ destination);
							recomm_authorized = false;
						}
						else
							System.out.println("Pump " + destination
									+ " not head of queue...");
					}
					else
						System.out.println("Pump " + destination
								+ " already commissioned...");
				}
			}
		}
		catch (ClassCastException e)
		{
			LOGGER.error(LogHelper.LOG_LAYER_ONE
					+ "Wrong payload type to recommissionPump()...");
		}
	}

	public void validateRecommPassword(MessagePayload data)
	{
		//data contains a Password
		//sets recomm_authorized to true
		//if password valid
		try
		{
			if (data != null)
			{
				Password pwd = (Password) data;
				int destination = pwd.getID();
				if (register_list.indexOf(new Register(destination)) > -1)
				{
					boolean isValid = pwd.checkPassword(this.recomm_password);

					if (isValid)
					{
						System.out.println("Sending Valid password Request");
						recomm_authorized = true;

						ControlMessage message = new ControlMessage(
								Messages.VALID, data);
						if (registerServer.sendMessage(message, destination) != 0)
							System.out
									.println("Failed sending recomm password validation signal to register: "
											+ destination);
					}
					else
					{
						
						recomm_authorized = false;
					}
				}
			}
		}
		catch (ClassCastException e)
		{
			LOGGER.error(LogHelper.LOG_LAYER_ONE
					+ "Wrong payload type to validateRecommPassword()...");
		}
	}

	public void changeRecommPassword(MessagePayload data)
	{
		//sets recomm_authorized to false
		try
		{
			if (data != null)
			{
				Password pwd = (Password) data;
				int destination = pwd.getID();
				int index = register_list.indexOf(new Register(destination));

				if (index != -1)
				{
					if (recomm_authorized)
					{
						recomm_password = pwd.getPwd("CS442Admin");
						System.out
								.println("Recommissioning password changed...");
						recomm_authorized = false;

						ControlMessage toRegister = new ControlMessage(
								Messages.VALID, null);
						registerServer.sendMessage(toRegister, destination);
					}
				}
			}
		}
		catch (ClassCastException e)
		{
			LOGGER.error(LogHelper.LOG_LAYER_ONE
					+ "Wrong payload type to changeRecommPassword()...");
		}
	}

	public void dequeueAssistance(MessagePayload data)
	{
		//data is a SelfAnnouncement
		//remove pump from queue
		try
		{
			if (data != null)
			{
				SelfAnnouncement pump = (SelfAnnouncement) data;
				int pumpID = pump.getIDofRequested();
				int regID = pump.getID();
				Pump toDequeue = new Pump(pumpID, null, 0, null);

				assistance_needed.remove(toDequeue);
				/*
								if (register_list.indexOf(new Register(regID)) != -1)
								{
									Pump head = assistance_needed.peek();
									if (head != null)
									{
										if (toDequeue.equals(head))
										{
											toDequeue = assistance_needed.poll();
										}
										else
											System.out.println("Cannot dequeue " + pumpID
													+ " because it is not head of queue...");
									}
									else
										System.out.println("Cannot dequeue " + pumpID
												+ " because queue is empty...");
								}
								*/
			}
		}
		catch (ClassCastException e)
		{
			LOGGER.error(LogHelper.LOG_LAYER_ONE
					+ "Wrong payload type to dequeueAssistance()...");
		}
	}

	public void announceTransaction(MessagePayload data)
	{
		try
		{
			if (data != null)
			{
				SelfAnnouncement pump = (SelfAnnouncement) data;
				int destination = pump.getIDofRequested();
				int sourceReg=pump.getID();				
				
				ControlMessage message = new ControlMessage(
						Messages.ANNOUNCETRANSACTION, data);

				//must use new send method specifically for transactions
				//it will return the Transaction requested
				if (pumpServer.sendMessage(message, destination) != 0)
					System.out
							.println("Failed sending Announce Transaction signal to Pump: "
									+ destination);
				
			}
		}
		catch (ClassCastException e)
		{
			LOGGER.error(
					"Error casting data to SelfAnnouncement in announceTransaction...",
					e);
		}
	}

	public void transactionReply(MessagePayload data)
	{
		try
		{
			if (data != null)
			{
				Transaction transaction = (Transaction) data;

				int pumpID = transaction.getPumpID();
				//destination should be register if positive
				//-1 indicates it is destined for this server
				int destination = transaction.getDestinationID();

				int index = pump_list.indexOf(new Pump(pumpID, null, 0.0,
						States.DEACTIVATED));

				if (index > -1)
				{
					Pump toChange = pump_list.get(index);
					toChange.setTransaction(transaction);

					if (destination > -1)
					{
						ControlMessage message = new ControlMessage(
								Messages.TRANSACTIONREPLY, data);
						if (pumpServer.sendMessage(message, destination) != 0)
							System.out
									.println("Failed sending Transaction to Register: "
											+ destination);
					}
				}
			}
		}
		catch (ClassCastException e)
		{
			LOGGER.error(
					"Error casting data to Transaction in transactionReply...",
					e);
		}
	}

	public void stateReply(MessagePayload data)
	{
		try
		{
			if (data != null)
			{
				PumpState state = (PumpState) data;
				int pumpID = state.getPumpID();
				//destination should be register if positive
				//-1 indicates it is destined for this server
				int destination = state.getDestinationID();
				int pumpIndex = pump_list.indexOf(new Pump(pumpID, null, 0.0,
						States.DEACTIVATED));
				int regIndex = register_list.indexOf(new Register(destination));

				if (pumpIndex > -1 && regIndex > -1)
				{
					Pump toChange = pump_list.get(pumpIndex);
					toChange.setState(state.getCurrentState());

					if (destination > -1)
					{
						ControlMessage message = new ControlMessage(
								Messages.STATEREPLY, data);
						if (pumpServer.sendMessage(message, destination) != 0)
							System.out
									.println("Failed sending PumpState to Register: "
											+ destination);
					}
				}
			}
		}
		catch (ClassCastException e)
		{
			LOGGER.error(
					"Error casting data to PumpState in transactionReply...", e);
		}
	}

	//For use with catching connection reset exception
	public void removePumpFromStation(int pumpID)
	{
		Pump pump = new Pump(pumpID, null, 0.0, States.DEACTIVATED);
		int index = pump_list.indexOf(pump);

		if (index > -1)
		{
			//remove from list
			pump_list.remove(index);
			//decrement pump counter
			pumpCount--;
		}
		else
			System.out.println("Couldn't remove pump from system. Pump ID "
					+ pumpID + " non-existant");
	}

	public void removeRegisterFromStation(int registerID)
	{
		Register reg = new Register(registerID);
		int index = register_list.indexOf(reg);

		if (index > -1)
		{
			//remove from list
			register_list.remove(index);
			//decrement pump counter
			registerCount--;
		}
		else
			System.out
					.println("Couldn't remove register from system. Register ID "
							+ registerID + " non-existant");
	}

	//////////////
	//////////////
	//Get Methods
	//////////////
	public boolean getRecommAuthorization()
	{
		return recomm_authorized;
	}

	public ArrayList<Pump> getPumpList()
	{
		return pump_list;
	}

	public ArrayList<Register> getRegisterList()
	{
		return register_list;
	}

	public int getPCount()
	{
		return pumpCount;
	}

	public int getRCount()
	{
		return registerCount;
	}

	public ConcurrentLinkedQueue<Pump> getDecomList()
	{
		return decomm_pumps;
	}

	public ConcurrentLinkedQueue<Pump> getAssistanceList()
	{
		return assistance_needed;
	}

	public Server_Comm getPServer()
	{
		return pumpServer;
	}

	public Server_Comm getRServer()
	{
		return registerServer;
	}

	public boolean getPServerStarted()
	{
		return pumpServerStarted;
	}

	public boolean getRServerStarted()
	{
		return registerServerStarted;
	}

	public String getRecommPassword()
	{
		return recomm_password;
	}

	/**
	 * @param args

	public static void main(String[] args)
	{
		// TODO Auto-generated method stub
		

	}
	 */
}
